import  wx
import wx.lib.agw.pybusyinfo as PBI
import wx.lib.agw.genericmessagedialog as GMD
import os
import shutil
from collections import Counter
from collections import defaultdict
import get_appdata_folder
from Bio.Align.Applications import ClustalwCommandline
from Bio.Seq import Seq
from Bio.Alphabet import IUPAC

from reportlab.graphics.charts.legends import LineLegend
from reportlab.graphics.charts.lineplots import LinePlot
from reportlab.graphics.shapes import Drawing, String
from reportlab.lib import colors
from reportlab.graphics import renderPDF


BUFFERED = 1
help_path = os.getcwd()

appdata_path = get_appdata_folder.get_appdata_directory()

class PlottingFrame(wx.Frame):
    def __init__(self, ids):
        wx.Frame.__init__(self, None, -1, "si-Fi scan results", size=(1100, 900))

        self.ids = ids
        self.max_x = 21
        self.scroll = wx.ScrolledWindow(self, -1)
        self.scroll.SetScrollbars(1, 1, 700, 750)
        colour = wx.Colour(250, 250, 250)
        self.scroll.SetBackgroundColour(colour)
        self.scroll.SetScrollRate(10,10)

        # Make plots
        self.create_pdf()

        # Display the plots
        sizer = wx.BoxSizer(wx.VERTICAL)
        self.scroll.SetSizer(sizer)
        box = wx.BoxSizer(wx.HORIZONTAL)
        gif = wx.Image(appdata_path + '\\files\\siFi_Plot.png', wx.BITMAP_TYPE_PNG).ConvertToBitmap()
        pic = wx.StaticBitmap(self.scroll, -1, gif, (270, 40),
                         (gif.GetWidth(), gif.GetHeight()))
        box.Add(pic, 0, wx.ALIGN_CENTER_VERTICAL)
        sizer.Add(box, 0, wx.CENTER|wx.ALL, 10)

        # Otherwise no scrolling
        self.scroll.SetFocusIgnoringChildren()


        self.build_menu()

    def create_pdf(self):
        """Creates a PDF from all plots."""
        self.draw = Drawing(1000, 1000)

        # Legend
        legend = LineLegend()
        legend.fontSize = 16
        legend.alignment = 'right'
        legend.x = 150
        legend.y = 980
        #legend.fontName = 'Helvetica'
        my_colors    = colors.blue, colors.red, colors.white, colors.white
        my_labels  = 'Total number of siRNA hits', 'Efficient siRNA hits', 'X-axis = Query sequence coordinates', 'Y-axis = Number of siRNA with hits to the subject'
        legend.colorNamePairs  = [(my_colors[i], my_labels[i]) for i in xrange(4)]
        legend.columnMaximum = 2
        self.draw.add(legend)

        data = []
        x = 50
        y = 800
        for plot_hits in self.ids:

            plott_all = self.make_all_plot(plot_hits)
            plot_eff = self.make_eff_plot(plot_hits)
            data.append(plott_all)
            data.append(plot_eff)
            self.make_line_plot(x, y, data, plot_hits)
            self.max_x = 21
            y -= 160
            data = []

        self.draw.save(formats=['pdf', 'png'],outDir=None, fnRoot = appdata_path + '\\files\\siFi_Plot')


    def make_line_plot(self, x, y, data, hit_name):
        """Creates a LinePlot with reportlab."""

        # Plot site and position
        line_plot = LinePlot()
        line_plot.x = x                 # left, right
        line_plot.y = y                 # up, down
        line_plot.width = 900
        line_plot.height = 100          # 100

        line_plot.strokeColor = colors.black
        line_plot.fillColor = colors.lightyellow

        # Line settings
        line_plot.lines[0].strokeColor = colors.blue
        line_plot.lines[1].strokeColor = colors.red
        line_plot.lines[0].strokeWidth = 2
        line_plot.lines[1].strokeWidth = 2

        # Data
        line_plot.data = data

        # Axis settings
        line_plot.yValueAxis.valueSteps = [0, self.max_x]
        line_plot.xValueAxis.labels.fontSize = 16
        line_plot.yValueAxis.labels.fontSize = 16
        line_plot.yValueAxis.strokeWidth = 2
        line_plot.xValueAxis.strokeWidth = 2
        line_plot.yValueAxis.valueMax = self.max_x + 10

        # Plot title
        s = String(x, y+105,str(hit_name), fontSize=16, fillColor=colors.black)

        # Add everything
        self.draw.add(s)
        self.draw.add(line_plot)


    def make_all_plot(self, id):
        "Count all hits per position and append to a list for plotting."
        f_bowtie = open(appdata_path + '\\files\\bowtie_parsed.txt', 'r')
        data = f_bowtie.readlines()
        f_seq = open(appdata_path + '\\files\\query_seq.txt', 'r')
        self.query_sequence = f_seq.read()
        f_seq.close()
        f_bowtie.close()

        l_all = []
        self.plot_all = []

        for i in data:
            i = i.strip()
            i = i.split('\t')
            if i[2] == id:
                start = self.query_sequence.find(str(i[3]))
                if start == -1:
                    myseq = Seq(str(i[3]), IUPAC.unambiguous_dna)
                    myseq = myseq.reverse_complement()
                    start = self.query_sequence.find(str(myseq))
                numbers = range(int(start),int(start)+21)
                for x in numbers:
                    l_all.append(x)

        l_all.sort()
        counter_all = Counter(l_all)
        counter_dict = dict(counter_all)
        for pos in range(len(self.query_sequence)+1):
            if counter_dict.get(pos) == None:
                self.plot_all.append((pos, 0))
            else:
                self.plot_all.append((pos, counter_dict.get(pos)))
                if counter_dict.get(pos) > self.max_x:
                    self.max_x = counter_dict.get(pos)


        return self.plot_all

    def make_eff_plot(self, id):
        "Count efficient hits per position and append to a list for plotting."
        f_bowtie = open(appdata_path + '\\files\\bowtie_parsed.txt', 'r')
        data = f_bowtie.readlines()
        f_seq = open(appdata_path + '\\files\\query_seq.txt', 'r')
        self.query_sequence = f_seq.read()
        f_seq.close()
        f_bowtie.close()

        l_eff = []
        self.plot_eff = []

        for i in data:
            i = i.strip()
            i = i.split('\t')
            if i[2] == id:
                if i[4] == 'EFF':
                    start = self.query_sequence.find(str(i[3]))
                    if start == -1:
                        myseq = Seq(str(i[3]), IUPAC.unambiguous_dna)
                        myseq = myseq.reverse_complement()
                        start = self.query_sequence.find(str(myseq))
                    numbers = range(int(start),int(start)+21)
                    for x in numbers:
                        l_eff.append(x)

        l_eff.sort()
        counter_eff = Counter(l_eff)
        counter_dict = dict(counter_eff)
        for pos in range(len(self.query_sequence)+1):
            if counter_dict.get(pos) == None:
                self.plot_eff.append((pos, 0))
            else:
                self.plot_eff.append((pos, counter_dict.get(pos)))

        return self.plot_eff


    def build_menu(self):
        # Create Menu Bar
        self.menuBar = wx.MenuBar()
        # Create Menu1 from left
        menu1 = wx.Menu()

        menu1.Append(101, 'Save as PDF', 'Save Plot as PDF')
        menu1.Append(102, 'Print PDF', 'Print Plot as PDF')
        menu1.Append(103, 'E&xit', 'Enough of this already!')
        # Create Menu2 from left
        menu2 = wx.Menu()
        menu2.Append(300, 'Help', 'Help')
        # Create Menu3 from left
        menu3 = wx.Menu()
        # Open File for Menu names of hits
        hits = self.ids
        id = 400
        for menu_id in hits:
            menu_id = menu_id.strip()
            menu_id = menu_id.split('\t')
            menu3.Append(id, str(menu_id[0]), str(menu_id[0]))
            self.Bind(wx.EVT_MENU, self.do_alignment, id=id)
            id = id + 1
        # Append all Menus
        self.menuBar.Append(menu1, "File")
        self.menuBar.Append(menu3, "Alignment")
        self.menuBar.Append(menu2, '&Help')

        # # Bind all  Menus
        self.Bind(wx.EVT_MENU, self.OnSaveFile, id=101)
        self.Bind(wx.EVT_MENU, self.OnPrintPDF, id=102)
        self.Bind(wx.EVT_MENU, self.OnFileExit, id=103)
        self.Bind(wx.EVT_MENU, self.OnHelp, id=300)

        self.SetMenuBar(self.menuBar)

    def do_alignment(self, event):
        # Get hit
        menuItem = self.menuBar.FindItemById(event.GetId())
        menuItem = '>' + menuItem.GetText()[0:]
        # Get DB
        f_db = open(appdata_path + '\\files\\last_db.txt', 'r')
        db = f_db.read() + '_index'
        # Get query sequence
        f_seq = open(appdata_path + '\\files\\query_seq.txt', 'r')
        query_seq = f_seq.read()
        # Switch to appdata folder
        os.chdir(appdata_path + '\\database\\')
        busy2 = PBI.PyBusyInfo('Please wait.\nDepending on sequence length, it will take awhile.', parent=None, title="Creating Alignment")
        wx.Yield()
        cursor = wx.StockCursor(wx.CURSOR_WAIT)
        self.SetCursor(cursor)

        cmd = "bowtie-inspect -a 0 " + db
        lst = os.popen(cmd).readlines()
        try:
            index = lst.index(menuItem + '\n')
            hit_seq = lst.pop(index+1)
            f_align = open(appdata_path + '\\database\\clustalw_input.txt', 'w')
            f_align.write('>RNAi_query_sequence\n')
            f_align.write(query_seq + '\n')
            f_align.write(menuItem + '\n')
            f_align.write(hit_seq)
            f_align.close()

            # Start clustalw alignment
            clustalw_exe = appdata_path + '\\database\\clustalw2.exe'
            clustalw_cline = ClustalwCommandline(clustalw_exe, infile="clustalw_input.txt")
            stdout, stderr = clustalw_cline()

            # Open alignment
            f_align = open(appdata_path + '\\database\\clustalw_input.aln', 'r')
            align = f_align.read()
            del busy2
            cursor = wx.StockCursor(wx.CURSOR_DEFAULT)
            self.SetCursor(cursor)
            dlg_align = wx.lib.dialogs.ScrolledMessageDialog(self, str(align), "Pairwise Alignment",
                                                            size = (1000,800))

            children = dlg_align.GetChildren()
            textCtrl = children[0]
            textCtrl.SetFont(wx.Font(10, wx.DEFAULT, wx.NORMAL, wx.NORMAL, 0, "Courier New"))
            dlg_align.ShowModal()
            dlg_align.Destroy()

        except ValueError:
            dlg = wx.MessageDialog(self, 'Sorry, hit not found in database.',
                               'Not found',
                               wx.OK | wx.ICON_INFORMATION)
            dlg.ShowModal()
            dlg.Destroy()

    def OnPrintPDF(self, event):
        """Open PDF in default PDF Viewer."""
        try:
            os.startfile(appdata_path + '\\files\\siFi_Plot.pdf')
        except:
            dlg_no = GMD.GenericMessageDialog(self, "Could not find PDF Viewer.",
                                           "No PDF Viewer!",
                                       wx.ICON_ERROR| wx.OK)
            dlg_no.ShowModal()
            dlg_no.Destroy()


    def OnSaveFile(self, event):
        """Save plots as PDF."""
        wildcard_pdf = "PDF files (*.pdf)|*.pdf|"    \
           "All files (*.*)|*.*"

        dlg_save = wx.FileDialog(
            self, message="Save file as ...", defaultDir=os.getcwd(),
            defaultFile="", wildcard=wildcard_pdf, style=wx.SAVE
            )
        if dlg_save.ShowModal() == wx.ID_OK:
            pdf_dir = dlg_save.GetPath()
            dlg_save.Destroy()
            try:
                shutil.copyfile(appdata_path + '\\files\\siFi_Plot.pdf', pdf_dir)
                dlg_yes = GMD.GenericMessageDialog(self, "File saved!",
                                           "File saved!",
                                       wx.ICON_INFORMATION| wx.OK)
                dlg_yes.ShowModal()
                dlg_yes.Destroy()
            except:
                dlg_no = GMD.GenericMessageDialog(self, "Sorry, file could not be saved.",
                                           "Saving not possible",
                                       wx.ICON_ERROR| wx.OK)
                dlg_no.ShowModal()
                dlg_no.Destroy()
        else:
            dlg_no = GMD.GenericMessageDialog(self, "Sorry, file could not be saved.",
                                           "Saving not possible",
                                       wx.ICON_ERROR| wx.OK)
            dlg_no.ShowModal()
            dlg_no.Destroy()

    def OnFileExit(self, event):
        self.Close()

    def OnHelp(self, event):
        self.InitHelp()

    def InitHelp(self):
        def _addBook(filename):
            if not self.help.AddBook(filename):
                wx.MessageBox("Unable to open: " + filename,
                              "Error", wx.OK|wx.ICON_EXCLAMATION)

        self.help = wx.html.HtmlHelpController()

        _addBook(help_path + "\\help\\testing.hhp")
        self.OnShowHelpContents()

    def OnShowHelpContents(self):
        self.help.Display(help_path + "\\help\\graphic.html")

#if __name__ == '__main__':
#    app = wx.PySimpleApp()
#    frame = PlottingFrame()
#    frame.Show(True)
#    app.MainLoop()